package com.wcpdoc.exam.api.controller;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.excel.EasyExcel;
import com.wcpdoc.base.entity.Org;
import com.wcpdoc.base.entity.User;
import com.wcpdoc.base.service.OrgService;
import com.wcpdoc.base.service.UserService;
import com.wcpdoc.core.util.DateUtil;
import com.wcpdoc.core.util.ValidateUtil;
import com.wcpdoc.exam.api.controller.excel.UserEntity;
import com.wcpdoc.exam.core.cache.QuestionCache;
import com.wcpdoc.exam.core.entity.*;
import com.wcpdoc.exam.core.service.ExamService;
import com.wcpdoc.exam.core.service.MyExamService;
import com.wcpdoc.exam.core.service.MyQuestionService;
import com.wcpdoc.exam.core.util.QuestionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import com.wcpdoc.core.controller.BaseController;
import com.wcpdoc.core.entity.PageIn;
import com.wcpdoc.core.entity.PageOut;
import com.wcpdoc.core.entity.PageResult;
import com.wcpdoc.core.entity.PageResultEx;
import com.wcpdoc.core.exception.MyException;
import com.wcpdoc.exam.report.service.ReportService;

/**
 * 成绩报表控制层
 * <p>
 * v1.0 zhanghc 2017年8月29日下午2:03:36
 */
@Controller
@RequestMapping("/api/report")
public class ApiReportController extends BaseController {
    private static final Logger log = LoggerFactory.getLogger(ApiReportController.class);

    @Resource
    private ReportService reportService;

    @Resource
    private UserService userService;

    @Resource
    private OrgService orgService;

    @Resource
    private MyExamService myExamService;
    @Resource
    private MyQuestionService myQuestionService;
    @Resource
    private ExamService examService;

    /**
     * 用户首页
     * <p>
     * v1.0 chenyun 2021年12月10日上午10:14:34
     *
     * @return PageResult
     */
    @RequestMapping("/user/home")
    @ResponseBody
    public PageResult userHome() {
        try {
            return PageResultEx.ok().data(reportService.userHome());
        } catch (MyException e) {
            log.error("用户首页错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("用户首页错误：", e);
            return PageResult.err();
        }
    }

    /**
     * 管理员首页
     * <p>
     * v1.0 chenyun 2021年12月10日上午10:14:34
     *
     * @return PageResult
     */
    @RequestMapping("/admin/home")
    @ResponseBody
    public PageResult adminHome() {
        try {
            return PageResultEx.ok().data(reportService.adminHome());
        } catch (MyException e) {
            log.error("管理员首页错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("管理员首页错误：", e);
            return PageResult.err();
        }
    }

    /**
     * 子管理员首页
     * <p>
     * v1.0 chenyun 2021年12月10日上午10:14:34
     *
     * @return PageResult
     */
    @RequestMapping("/subAdmin/home")
    @ResponseBody
    public PageResult subAdminHome() {
        try {
            return PageResultEx.ok().data(reportService.subAdminHome());
        } catch (MyException e) {
            log.error("子管理员首页错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("子管理员首页错误：", e);
            return PageResult.err();
        }
    }

    /**
     * 阅卷用户首页
     * <p>
     * v1.0 chenyun 2021年12月10日上午10:14:34
     *
     * @return PageResult
     */
    @RequestMapping("/markUser/home")
    @ResponseBody
    public PageResult markUserHome() {
        try {
            return PageResultEx.ok().data(reportService.markUserHome());
        } catch (MyException e) {
            log.error("阅卷用户首页错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("阅卷用户首页错误：", e);
            return PageResult.err();
        }
    }

//    /**
//     * 服务器参数 // 第三方dll有bug
//     *
//     * v1.0 chenyun 2021年12月10日上午10:14:34
//     * @return PageResult
//     */
//    @RequestMapping("/server/parm")
//    @ResponseBody
//    public PageResult serverParm() {
//        try {
//        	return null;
////            return PageResultEx.ok().data(serverParmService.getList());
//        } catch (MyException e) {
//            log.error("首页服务器参数统计错误：{}", e.getMessage());
//            return PageResult.err().msg(e.getMessage());
//        } catch (Exception e) {
//            log.error("首页服务器参数统计错误：", e);
//            return PageResult.err();
//        }
//    }

    /**
     * 慢接口日志
     * <p>
     * v1.0 chenyun 2021-12-15 13:49:29
     *
     * @return PageResult
     */
    @RequestMapping("/server/log")
    @ResponseBody
    public PageResult serverLog() {
        try {
            return PageResultEx.ok().data(reportService.serverLog());
        } catch (MyException e) {
            log.error("首页慢接口日志统计错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("首页慢接口日志统计错误：", e);
            return PageResult.err();
        }
    }

    /**
     * 试题统计
     * <p>
     * v1.0 chenyun 2021-12-15 13:44:47
     *
     * @return PageResult
     */
    @RequestMapping("/question/statis")
    @ResponseBody
    public PageResult questionStatis(Integer questionTypeId) {
        try {
            return PageResultEx.ok().data(reportService.questionStatis(questionTypeId));
        } catch (MyException e) {
            log.error("试题统计错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("试题统计错误：", e);
            return PageResult.err();
        }
    }


    /**
     * 考试统计
     * <p>
     * v1.0 chenyun 2021-12-15 13:44:47
     *
     * @param examId
     * @return PageResult
     */
    @RequestMapping("/exam/statis")
    @ResponseBody
    public PageResult examStatis(Integer examId) {
        try {
            return PageResultEx.ok().data(reportService.examStatis(examId));
        } catch (MyException e) {
            log.error("考试统计错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("考试统计错误：", e);
            return PageResult.err();
        }
    }

    /**
     * 考试排名导出
     */
    @RequestMapping("/exam/export")
    public void exportExcel(HttpServletResponse response, Integer examId) {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");

        List<Map<String, Object>> data = reportService.exportFile(examId);
        log.info("------------222");
        log.info(data.toString());
        List<UserEntity> dataList = new ArrayList<>();
        for (Map<String, Object> map : data) {
            UserEntity dataItem = new UserEntity();
            /*2024年1月3日 增加导出用户信息*/
            dataItem.setLoginName(String.valueOf(map.get("loginName")));
            dataItem.setSex(String.valueOf(map.get("sex")));
            dataItem.setLabelName(String.valueOf(map.get("labelName")));
            /*end 增加导出用户信息*/
            dataItem.setMyExamNo(String.valueOf(map.get("myExamNo")));
            dataItem.setUserName(String.valueOf(map.get("userName")));
            dataItem.setOrgName(String.valueOf(map.get("orgName")));
            dataItem.setMyExamTotalScore(String.valueOf(map.get("myExamTotalScore")));
            dataItem.setMyExamState(String.valueOf(map.get("myExamState")));
            dataItem.setMyExamMarkState(String.valueOf(map.get("myExamMarkState")));
            dataItem.setMyExamStartTime(String.valueOf(map.get("myExamStartTime")));
            dataItem.setMyExamEndTime(String.valueOf(map.get("myExamEndTime")));
            dataItem.setMyExamMarkStartTime(String.valueOf(map.get("myExamMarkStartTime")));
            dataItem.setMyExamMarkEndTime(String.valueOf(map.get("myExamMarkEndTime")));
            dataList.add(dataItem);
        }

        // 文件名
        String fileName;
        fileName = "考试排名";
        try {
            // 文件名，编码格式
            fileName = URLEncoder.encode(fileName, "UTF-8");

            // 文件格式
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

            // 使用EasyExcel工具写excel
            EasyExcel.write(response.getOutputStream(), UserEntity.class).sheet("logs").doWrite(dataList);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 考试排名
     * <p>
     * v1.0 chenyun 2021-12-15 13:44:47
     *
     * @return PageResult
     */
    @RequestMapping("/exam/rankListpage")
    @ResponseBody
    public PageResult examRankListpage() {
        try {// 不校验，任何时候都能查询
            PageOut pageOut = reportService.examRankListpage(new PageIn(request));
            for (Map<String, Object> map : pageOut.getList()) {
                Integer examMarkType = (Integer) map.get("examMarkType");
                Integer examMarkState = (Integer) map.get("examMarkState");
                if (examMarkType == 2 && examMarkState != 3) {// 如果是主观题试卷，且考试未结束，不显示分数
                    map.put("myExamTotalScore", null);// 阅完一张会打分，但是会二次修改分数，不应该显示中间状态
                }
            }
            return PageResultEx.ok().data(pageOut);
        } catch (MyException e) {
            log.error("考试排名错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("考试排名错误：", e);
            return PageResult.err();
        }
    }

    /**
     * 错题分析
     *
     * v1.0 chenyun 2021-12-15 13:44:47
     * @return PageResult
     */
//    @RequestMapping("/exam/questionErrList")
//    @ResponseBody
//    public PageResult questionErrList(Integer examId) {
//        try {
//            return PageResultEx.ok().data(reportService.questionErrList(examId));
//        } catch (MyException e) {
//            log.error("错题分析统计错误：{}", e.getMessage());
//            return PageResult.err().msg(e.getMessage());
//        } catch (Exception e) {
//            log.error("错题分析统计错误：", e);
//            return PageResult.err();
//        }
//    }

    /**
     * 分数统计
     *
     * v1.0 zhanghc 2018年11月24日上午9:13:22
     * @param id
     * @return PageResult
     */
/*    @RequestMapping("/count")
    @ResponseBody
    public PageResult count(Integer examId) {
        try {
            return PageResultEx.ok().data(reportService.count(examId));
        } catch (MyException e) {
            log.error("分数统计错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("分数统计错误：", e);
            return PageResult.err();
        }
    }*/

    /**
     * @param userId
     * @return com.wcpdoc.core.entity.PageResult
     * @author 王晶
     * @date 2024/4/23 22:09
     */
    @PostMapping("/getUser/{userId}")
    @ResponseBody
    public PageResult getUser(@PathVariable Integer userId) {
        try {

            User user = userService.getEntity(userId);
            Org org = null;
            if (user.getOrgId() != null) {
                org = orgService.getEntity(user.getOrgId());
            }

            PageResultEx pageResult = PageResultEx.ok()
                    .addAttr("id", user.getId())
                    .addAttr("name", user.getName())
                    .addAttr("sex", user.getSex())
                    .addAttr("loginName", user.getLoginName())
                    .addAttr("orgId", user.getOrgId())
                    .addAttr("orgName", org == null ? null : org.getName())
                    .addAttr("state", user.getState())
                    .addAttr("userIds", user.getUserIds())
                    .addAttr("orgIds", user.getOrgIds())
                    .addAttr("labelId", user.getLabelId())
                    .addAttr("phone", user.getPhone());
            return pageResult;
        } catch (MyException e) {
            log.error("统计：查看考卷：用户获取错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("统计：查看考卷：用户获取错误：", e);
            return PageResult.err();
        }
    }


    /**
     * @param userId
     * @param examId
     * @return com.wcpdoc.core.entity.PageResult
     * @Description: 获取试卷信息
     * @author 王晶
     * @date 2024/4/23 22:17
     */
    @PostMapping("/getExam/{userId}/{examId}")
    @ResponseBody
    public PageResult get(@PathVariable Integer userId, @PathVariable Integer examId) {
        try {
            MyExam myExam = myExamService.getMyExam(examId, userId);
            if (myExam == null) {
                throw new MyException("无查阅权限");
            }
            Exam exam = examService.getEntity(examId);
            return PageResultEx.ok()
                    .addAttr("examMarkState", exam.getMarkState()) // 页面控制是否显示错题
                    .addAttr("examScoreState", exam.getScoreState())// 页面控制是否显示错题
                    .addAttr("examRankState", exam.getRankState())// 页面控制是否显示排名
                    .addAttr("examStartTime", DateUtil.formatDateTime(exam.getStartTime()))
                    .addAttr("examEndTime", DateUtil.formatDateTime(exam.getEndTime()))// 考试结束时间（进入我的试卷使用）
                    .addAttr("examMarkStartTime", ValidateUtil.isValid(exam.getMarkStartTime()) ? DateUtil.formatDateTime(exam.getMarkStartTime()) : null)
                    .addAttr("examMarkEndTime", ValidateUtil.isValid(exam.getMarkEndTime()) ? DateUtil.formatDateTime(exam.getMarkEndTime()) : null)// 如果是交卷后公布，但试卷是主观题试卷，页面提示几点之后查询
                    .addAttr("examName", exam.getName())// 考试名称
                    .addAttr("answerStartTime", ValidateUtil.isValid(myExam.getAnswerStartTime()) ? DateUtil.formatDateTime(myExam.getAnswerStartTime()) : null)
                    .addAttr("answerEndTime", ValidateUtil.isValid(myExam.getAnswerEndTime()) ? DateUtil.formatDateTime(myExam.getAnswerEndTime()) : null)
                    .addAttr("markStartTime", ValidateUtil.isValid(myExam.getMarkStartTime()) ? DateUtil.formatDateTime(myExam.getMarkStartTime()) : null)
                    .addAttr("markEndTime", ValidateUtil.isValid(myExam.getMarkEndTime()) ? DateUtil.formatDateTime(myExam.getMarkEndTime()) : null)
                    .addAttr("objectiveScore", myExam.getObjectiveScore())
                    .addAttr("totalScore", myExam.getTotalScore())
                    .addAttr("answerState", myExam.getAnswerState())
                    .addAttr("state", myExam.getState())
                    .addAttr("markState", myExam.getMarkState())
                    .addAttr("no", exam.getRankState() == 1 ? myExam.getNo() : null)
                    .addAttr("userNum", exam.getRankState() == 1 ? myExamService.getList(examId).size() : null);
        } catch (MyException e) {
            log.error("统计：查看考卷: 获取我的考试错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("统计：查看考卷: 获取我的考试错误：", e);
            return PageResult.err();
        }
    }

    /**
     * @param userId
     * @param examId
     * @return com.wcpdoc.core.entity.PageResult
     * @Description: 显示标准答案
     * @author 王晶
     * @date 2024/4/23 22:16
     */
    @PostMapping("/paper/{userId}/{examId}")
    @ResponseBody
    public PageResult paper(@PathVariable Integer userId, @PathVariable Integer examId) {
        try {
            // 校验数据有效性
            if (!ValidateUtil.isValid(examId)) {
                throw new MyException("参数错误：examId");
            }

            MyExam _myExam = myExamService.getMyExam(examId, userId);
            if (_myExam == null) {
                throw new MyException("无查阅权限");
            }
            Exam exam = examService.getEntity(examId);
            if (exam.getEndTime().getTime() > System.currentTimeMillis()) {
                throw new MyException("获取试卷:考试未结束");
            }

            // 组装试卷
            List<Map<String, Object>> paper = new ArrayList<>();
            List<MyQuestion> myQuestionList = myQuestionService.getList(examId, userId);


            for (MyQuestion _myQuestion : myQuestionList) {
                Map<String, Object> myQuestion = new HashMap<>();
                if (_myQuestion.getType() == 1) {
                    myQuestion.put("type", _myQuestion.getType());
                    myQuestion.put("chapterName", _myQuestion.getChapterName());
                    myQuestion.put("chapterTxt", _myQuestion.getChapterTxt());
                } else {
                    myQuestion.put("type", _myQuestion.getType());
                    myQuestion.put("questionId", _myQuestion.getQuestionId());

                    Question question = QuestionCache.getQuestion(_myQuestion.getQuestionId());// 已关联考试的试题不会改变，缓存起来加速查询。
                    myQuestion.put("questionType", question.getType());
                    myQuestion.put("markType", question.getMarkType());
                    myQuestion.put("title", question.getTitle());
                    myQuestion.put("markOptions", _myQuestion.getMarkOptions());
                    myQuestion.put("score", _myQuestion.getScore());
                    myQuestion.put("analysis", question.getAnalysis());
                    myQuestion.put("userScore", _myQuestion.getUserScore());
                    {// 选项
                        List<String> options = new ArrayList<>();
                        if (QuestionUtil.hasSingleChoice(question) || QuestionUtil.hasMultipleChoice(question)) {// 如果是单选或多选，添加选项字段
                            List<QuestionOption> questionOptionList = QuestionCache.getOption(_myQuestion.getQuestionId());
                            if (ValidateUtil.isValid(_myQuestion.getOptionsNo())) {// 选项乱序
                                for (int optionsNo : _myQuestion.getOptionsNo()) {// 4,1,2,3
                                    QuestionOption questionOption = questionOptionList.get(optionsNo - 1);// 先放第4个
                                    options.add(questionOption.getOptions());
                                }
                            } else {
                                for (QuestionOption questionOption : questionOptionList) {// 常规顺序
                                    options.add(questionOption.getOptions());
                                }
                            }

                        }
                        myQuestion.put("options", options);
                    }

                    {// 用户答案
                        List<String> userAnswerList = new ArrayList<>();
                        if (ValidateUtil.isValid(_myQuestion.getUserAnswer())) {
                            if (QuestionUtil.hasTrueFalse(question) || QuestionUtil.hasQA(question)) {// 判断、问答
                                userAnswerList.add(_myQuestion.getUserAnswer());
                            } else if (QuestionUtil.hasSingleChoice(question)) {// 单选
                                if (ValidateUtil.isValid(_myQuestion.getOptionsNo())) {// 选项乱序：4,1,3,2 ，填写答案：B，回显：D
                                    userAnswerList.add(_myQuestion.getOptionsNoCache().get(_myQuestion.getUserAnswer()));
                                } else {
                                    userAnswerList.add(_myQuestion.getUserAnswer());
                                }
                            } else if (QuestionUtil.hasMultipleChoice(question)) {//多选
                                String[] userAnswers = _myQuestion.getUserAnswer().split(",");
                                if (ValidateUtil.isValid(_myQuestion.getOptionsNo())) {
                                    for (String userAnswer : userAnswers) {
                                        userAnswerList.add(_myQuestion.getOptionsNoCache().get(userAnswer));
                                    }
                                } else {
                                    Collections.addAll(userAnswerList, userAnswers);
                                }
                            } else if (QuestionUtil.hasFillBlank(question)) {// 填空
                                Collections.addAll(userAnswerList, _myQuestion.getUserAnswer().split("\n", -1));
                            }
                        }
                        myQuestion.put("userAnswers", userAnswerList);
                    }

                    {// 标准答案
                        List<String> answerList = new ArrayList<>();

                        List<QuestionAnswer> questionAnswerList = QuestionCache.getAnswer(_myQuestion.getQuestionId());
                        for (QuestionAnswer answer : questionAnswerList) {
                            if (QuestionUtil.hasTrueFalse(question)
                                    || (QuestionUtil.hasQA(question) && QuestionUtil.hasSubjective(question))) {
                                answerList.add(answer.getAnswer());
                            } else if (QuestionUtil.hasSingleChoice(question)) {
                                if (ValidateUtil.isValid(_myQuestion.getOptionsNo())) {
                                    answerList.add(_myQuestion.getOptionsNoCache().get(answer.getAnswer()));
                                } else {
                                    answerList.add(answer.getAnswer());
                                }
                            } else if (QuestionUtil.hasMultipleChoice(question)) {
                                String[] answers = answer.getAnswer().split(",");
                                if (ValidateUtil.isValid(_myQuestion.getOptionsNo())) {
                                    for (String _answer : answers) {
                                        answerList.add(_myQuestion.getOptionsNoCache().get(_answer));
                                    }
                                } else {
                                    Collections.addAll(answerList, answers);
                                }
                            } else if (QuestionUtil.hasFillBlank(question) || (QuestionUtil.hasQA(question)
                                    && QuestionUtil.hasObjective(question))) {
                                answerList.add(answer.getAnswer());
                            }
                        }

                        myQuestion.put("answers", answerList);
                    }
                }
                paper.add(myQuestion);
            }

            return PageResultEx.ok().data(paper);
        } catch (MyException e) {
            log.error("统计：查看考卷:我的试卷错误：{}", e.getMessage());
            return PageResult.err().msg(e.getMessage());
        } catch (Exception e) {
            log.error("统计：查看考卷:我的试卷错误：", e);
            return PageResult.err();
        }
    }
}
